{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "1Z6Wtb_jisbA"
      },
      "source": [
        "##### Copyright 2019 The TensorFlow Authors."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "cellView": "form",
        "id": "QUyRGn9riopB"
      },
      "outputs": [],
      "source": [
        "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n",
        "# you may not use this file except in compliance with the License.\n",
        "# You may obtain a copy of the License at\n",
        "#\n",
        "# https://www.apache.org/licenses/LICENSE-2.0\n",
        "#\n",
        "# Unless required by applicable law or agreed to in writing, software\n",
        "# distributed under the License is distributed on an \"AS IS\" BASIS,\n",
        "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
        "# See the License for the specific language governing permissions and\n",
        "# limitations under the License."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "H1yCdGFW4j_F"
      },
      "source": [
        "# Готовые оценщики"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "PS6_yKSoyLAl"
      },
      "source": [
        "<table class=\"tfo-notebook-buttons\" align=\"left\">\n",
        "  <td>\n",
        "    <a target=\"_blank\" href=\"https://www.tensorflow.org/tutorials/estimator/premade\"><img src=\"https://www.tensorflow.org/images/tf_logo_32px.png\" />Смотреть на TensorFlow.org</a>\n",
        "  </td>\n",
        "  <td>\n",
        "    <a target=\"_blank\" href=\"https://colab.research.google.com/github/tensorflow/docs-l10n/blob/master/site/ru/tutorials/estimator/premade.ipynb\"><img src=\"https://www.tensorflow.org/images/colab_logo_32px.png\" />Запустить в Google Colab</a>\n",
        "  </td>\n",
        "  <td>\n",
        "    <a target=\"_blank\" href=\"https://github.com/tensorflow/docs-l10n/blob/master/site/ru/tutorials/estimator/premade.ipynb\"><img src=\"https://www.tensorflow.org/images/GitHub-Mark-32px.png\" />Смотреть исходные файлы на GitHub</a>\n",
        "  </td>\n",
        "  <td>\n",
        "    <a href=\"https://storage.googleapis.com/tensorflow_docs/docs-l10n/site/ru/tutorials/estimator/premade.ipynb\"><img src=\"https://www.tensorflow.org/images/download_logo_32px.png\" />Скачать ноутбук</a>\n",
        "  </td>\n",
        "</table>"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "8a2322303a3f"
      },
      "source": [
        "Note: Вся информация в этом разделе переведена с помощью русскоговорящего Tensorflow сообщества на общественных началах. Поскольку этот перевод не является официальным, мы не гарантируем что он на 100% аккуратен и соответствует [официальной документации на английском языке](https://www.tensorflow.org/?hl=en). Если у вас есть предложение как исправить этот перевод, мы будем очень рады увидеть pull request в [tensorflow/docs](https://github.com/tensorflow/docs) репозиторий GitHub. Если вы хотите помочь сделать документацию по Tensorflow лучше (сделать сам перевод или проверить перевод подготовленный кем-то другим), напишите нам на [docs-ru@tensorflow.org list](https://groups.google.com/a/tensorflow.org/forum/#!forum/docs-ru)."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "R4YZ_ievcY7p"
      },
      "source": [
        "Это руководство покажет вам как решить проблему классификации цветов ириса в TensorFlow с помощью оценщиков. Оценщик - это высокоуровневое представление полной модели TensorFlow, которое было разработано для простого масштабирования и асинхронного обучения. Подробнее см.[Оценщики](https://www.tensorflow.org/guide/estimator).\n",
        "\n",
        "Обратите внимание, что в TensorFlow 2.0 [Keras API](https://www.tensorflow.org/guide/keras) может выполнять многие из этих задач, и считается, что Keras API более простой для изучения. Если вы только начинаете свое обучение, мы рекомендуем вам начать с Keras. Для получения дополнительной информации о доступных API высокого уровня в TensorFlow 2.0 см. [Стандартизация для Keras](https://medium.com/tensorflow/standardizing-on-keras-guidance-on-high-level-apis-in-tensorflow-2-0-bad2b04c819a)."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "8IFct0yedsTy"
      },
      "source": [
        "## Импорт\n",
        "\n",
        "Для начала вы импортируете TensorFlow и ряд необходимых библиотек."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "jPo5bQwndr9P"
      },
      "outputs": [],
      "source": [
        "import tensorflow as tf\n",
        "\n",
        "import pandas as pd"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "c5w4m5gncnGh"
      },
      "source": [
        "## Датасет\n",
        "\n",
        "Пример программы в этом документе создает и тестирует модель, которая классифицирует цветы ириса на три разных вида в зависимости от размера их [чашелистиков](https://en.wikipedia.org/wiki/Sepal) и [лепестков](https://en.wikipedia.org/wiki/Petal).\n",
        "\n",
        "\n",
        "Вы обучите модель, используя набор данных Iris. Набор данных Iris содержит четыре признака и одну\n",
        "[метку](https://developers.google.com/machine-learning/glossary/#label).\n",
        "Четыре признака определяют следующие ботанические характеристики цветка ириса:\n",
        "\n",
        "* длина чашелистика\n",
        "* ширина чашелистика\n",
        "* длина лепестка\n",
        "* ширина лепестка\n",
        "\n",
        "Основываясь на этой информации, вы можете определить несколько полезных констант для анализа данных:\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "lSyrXp_He_UE"
      },
      "outputs": [],
      "source": [
        "CSV_COLUMN_NAMES = ['SepalLength', 'SepalWidth', 'PetalLength', 'PetalWidth', 'Species']\n",
        "SPECIES = ['Setosa', 'Versicolor', 'Virginica']"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "j6mTfIQzfC9w"
      },
      "source": [
        "Теперь загрузите и проанализируйте датасет Iris с помощью Keras и Pandas. Обратите внимание, что вы сохраняете отдельные датасеты для обучения и тестирования."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "PumyCN8VdGGc"
      },
      "outputs": [],
      "source": [
        "train_path = tf.keras.utils.get_file(\n",
        "    \"iris_training.csv\", \"https://storage.googleapis.com/download.tensorflow.org/data/iris_training.csv\")\n",
        "test_path = tf.keras.utils.get_file(\n",
        "    \"iris_test.csv\", \"https://storage.googleapis.com/download.tensorflow.org/data/iris_test.csv\")\n",
        "\n",
        "train = pd.read_csv(train_path, names=CSV_COLUMN_NAMES, header=0)\n",
        "test = pd.read_csv(test_path, names=CSV_COLUMN_NAMES, header=0)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "wHFxNLszhQjz"
      },
      "source": [
        "Вы можете проверить данные, чтобы увидеть, что у вас есть четыре столбца признаков с типа float и одна метка типа int32."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "WOJt-ML4hAwI"
      },
      "outputs": [],
      "source": [
        "train.head()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "jQJEYfVvfznP"
      },
      "source": [
        "Для каждого набора данных отделите метки."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "zM0wz2TueuA6"
      },
      "outputs": [],
      "source": [
        "train_y = train.pop('Species')\n",
        "test_y = test.pop('Species')\n",
        "\n",
        "# Столбец метки теперь удален из признаков.\n",
        "train.head()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "jZx1L_1Vcmxv"
      },
      "source": [
        "## Введение в программирование с помощью оценщиков\n",
        "\n",
        "Теперь, когда у вас есть данные, вы можете создать модель с помощью оценщика TensorFlow. Оценщик - это любой класс, производный от `tf.estimator.Estimator`. TensorFlow предоставляет коллекцию `tf.estimator`(например, `LinearRegressor`) для реализации общих алгоритмов машинного обучения. Кроме того, вы можете написать свой [собственный оценщик](https://www.tensorflow.org/guide/custom_estimators).\n",
        "Для начала мы рекомендуем использовать готовые оценщики.\n",
        "\n",
        "Чтобы написать программу TensorFlow на основе готовых оценщиков, необходимо выполнить\n",
        "следующие шаги:\n",
        "\n",
        "* Создайте одну или несколько функций ввода.\n",
        "* Определите столбцы признаков модели.\n",
        "* Создайте оценщик, указав признаки и различные гиперпараметры.\n",
        "* Вызовите один или несколько методов объекта Estimator, передав соответствующую входную функцию как источник данных.\n",
        "\n",
        "Давайте посмотрим, как эти задачи реализованы для классификации Iris."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "2OcguDfBcmmg"
      },
      "source": [
        "## Создание функций ввода\n",
        "\n",
        "Вы должны создать функции ввода для предоставления данных для обучения, оценки и прогноза.\n",
        "\n",
        "**функция ввода** - это функция, возвращающая объект `tf.data.Dataset`, который выводит следующий двухэлементный кортеж:\n",
        "\n",
        "* [`features`](https://developers.google.com/machine-learning/glossary/#feature) - словарь Python, в котором:\n",
        "     * Каждый ключ - это имя признака.\n",
        "     * Каждое значение представляет собой массив, содержащий все значения этого признака.\n",
        "* `label` - Массив, содержащий значения [меток](https://developers.google.com/machine-learning/glossary/#label) для каждого примера.\n",
        "\n",
        "Чтобы продемонстрировать формат функции ввода, вот простой пример реализации:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "nzr5vRr5caGF"
      },
      "outputs": [],
      "source": [
        "def input_evaluation_set():\n",
        "    features = {'SepalLength': np.array([6.4, 5.0]),\n",
        "                'SepalWidth':  np.array([2.8, 2.3]),\n",
        "                'PetalLength': np.array([5.6, 3.3]),\n",
        "                'PetalWidth':  np.array([2.2, 1.0])}\n",
        "    labels = np.array([2, 1])\n",
        "    return features, labels"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "NpXvGjfnjHgY"
      },
      "source": [
        "Ваша функция ввода может генерировать словарь `features` и список `label` любым способом, который вы предпочитаете. Однако мы рекомендуем использовать [Dataset API] TensorFlow(https://www.tensorflow.org/guide/datasets), который может работать с различными форматами входных данных.\n",
        "\n",
        "`Dataset API` может работать с множеством распространенных случаев. Например, используя `Dataset API`, вы можете легко параллельно читать записи из большой коллекции файлов, объединив их в единый поток.\n",
        "\n",
        "Для простоты в этом примере вы будете загружать данные с помощью [pandas](https://pandas.pydata.org/) и создадите конвейер ввода в памяти:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "T20u1anCi8NP"
      },
      "outputs": [],
      "source": [
        "def input_fn(features, labels, training=True, batch_size=256):\n",
        "    \"\"\"Функция ввода для обучения или оценки\"\"\"\n",
        "    # Преобразуем входные данные в Dataset.\n",
        "    dataset = tf.data.Dataset.from_tensor_slices((dict(features), labels))\n",
        "\n",
        "    # Перемешаем и повторим данные, если мы в режиме обучения.\n",
        "    if training:\n",
        "        dataset = dataset.shuffle(1000).repeat()\n",
        "    \n",
        "    return dataset.batch(batch_size)\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "xIwcFT4MlZEi"
      },
      "source": [
        "## Определение столбцов признаков\n",
        "\n",
        "[**столбец функций**](https://developers.google.com/machine-learning/glossary/#feature_columns)\n",
        "- объект, описывающий, как модель должна использовать необработанные входные данные из словаря функций. Когда вы строите модель оценщика, вы передаете ей список столбцов признаков, которые описывают каждый признак, который должна использовать модель.\n",
        "Модуль `tf.feature_column` предлагает множество опций для представления данных в модели.\n",
        "\n",
        "Для Iris 4 необработанных признака представляют собой числовые значения, поэтому мы создадим список столбцов признаков, чтобы сообщить модели Оценщика, что каждый из четырех признаков должен быть представлен в виде float32. Следовательно, код для создания столбца признаков будет таким:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "ZTTriO8FlSML"
      },
      "outputs": [],
      "source": [
        "# Столбцы признаков описывают, как использовать входные данные.\n",
        "my_feature_columns = []\n",
        "for key in train.keys():\n",
        "    my_feature_columns.append(tf.feature_column.numeric_column(key=key))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "jpKkhMoZljco"
      },
      "source": [
        "Столбцы признаков могут быть гораздо сложнее, чем те, которые мы показываем здесь. Вы можете узнать больше о столбцах признаков в [этом руководстве](https://www.tensorflow.org/guide/feature_columns).\n",
        "\n",
        "Теперь, когда у вас есть описание того, как модель должна представлять необработанные\n",
        "признаки, вы можете построить оценщик."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "kuE59XHEl22K"
      },
      "source": [
        "## Инициализация оценщика\n",
        "\n",
        "Проблема распознования цветов ириса - это классическая проблема классификации. К счастью, TensorFlow\n",
        "предоставляет несколько готовых оценщиков классификации, в том числе:\n",
        "\n",
        "* `tf.estimator.DNNClassifier` для моделей глубокого обучения, которые выполняют мультиклассовую классификацию.\n",
        "* `tf.estimator.DNNLinearCombinedClassifier` для больших и глубоких моделей.\n",
        "* `tf.estimator.LinearClassifier` для классификаторов на основе линейных моделей.\n",
        "\n",
        "Для распознования цветов ириса лучшим выбором кажется `tf.estimator.DNNClassifier`.\n",
        "Вот пример создания этого эстиматора:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "qnf4o2V5lcPn"
      },
      "outputs": [],
      "source": [
        "# Создаем DNN с 2-мя скрытыми слоями с 30 и 10 скрытыми узлами в каждом.\n",
        "classifier = tf.estimator.DNNClassifier(\n",
        "    feature_columns=my_feature_columns,\n",
        "    # Два скрытых слоя по 30 и 10 узлов соответственно.\n",
        "    hidden_units=[30, 10],\n",
        "    # Модель должна выбирать между 3 классами.\n",
        "    n_classes=3)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "tzzt5nUpmEe3"
      },
      "source": [
        "## Обучение, оценка и прогноз\n",
        "\n",
        "Теперь, когда у вас есть объект оценщика, вы можете вызывать методы, чтобы сделать следующее:\n",
        "\n",
        "* Обучить модель.\n",
        "* Оценить обученную модель.\n",
        "* Использовать обученную модель, чтобы делать прогнозы."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "rnihuLdWmE75"
      },
      "source": [
        "### Обучение модели\n",
        "\n",
        "Обучите модель, вызвав метод `train` эстиматора следующим образом:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "4jW08YtPl1iS"
      },
      "outputs": [],
      "source": [
        "# обучение.\n",
        "classifier.train(\n",
        "    input_fn=lambda: input_fn(train, train_y, training=True),\n",
        "    steps=5000)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "ybiTFDmlmes8"
      },
      "source": [
        "Обратите внимание, что вы оборачиваете вызов `input_fn` в [`lambda функцию`](https://docs.python.org/3/tutorial/controlflow.html) для передачи аргументов в функцию ввода. Аргумент `steps` указывает методу прекратить обучение после ряда шагов обучения."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "HNvJLH8hmsdf"
      },
      "source": [
        "### Оценка обученной модели\n",
        "\n",
        "Теперь, когда модель обучена, вы можете получить некоторую статистику ее эффективности. Следующий блок кода оценивает точность обученной модели на тестовых данных:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "A169XuO4mKxF"
      },
      "outputs": [],
      "source": [
        "eval_result = classifier.evaluate(\n",
        "    input_fn=lambda: input_fn(test, test_y, training=False))\n",
        "\n",
        "print('\\nTest set accuracy: {accuracy:0.3f}\\n'.format(**eval_result))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "VnPMP5EHph17"
      },
      "source": [
        "В отличие от вызова метода `train`, вы не передаете аргумент `steps` для оценки. `input_fn` для выполняется только для одной [эпохи](https://developers.google.com/machine-learning/glossary/#epoch).\n",
        "\n",
        "Словарь `eval_result` содержит `average_loss`(средние потери на выборку), `loss`(средние потери на мини-пакет) и значение `global_step` оценщика(количество пройденных шагов обучения)."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "ur624ibpp52X"
      },
      "source": [
        "### Создание прогнозов (вывод) на основе обученной модели\n",
        "\n",
        "Теперь у вас есть обученная модель, которая дает хорошие результаты оценки.\n",
        "Вы можете использовать обученную модель, чтобы предсказать вид цветка ириса на основании некоторых немаркированных признаков. Как и в случае с обучением и оценкой, вы делаете прогнозы с использованием единственного вызова функции:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "wltc0jpgng38"
      },
      "outputs": [],
      "source": [
        "# Создание прогнозов на основе модели\n",
        "expected = ['Setosa', 'Versicolor', 'Virginica']\n",
        "predict_x = {\n",
        "    'SepalLength': [5.1, 5.9, 6.9],\n",
        "    'SepalWidth': [3.3, 3.0, 3.1],\n",
        "    'PetalLength': [1.7, 4.2, 5.4],\n",
        "    'PetalWidth': [0.5, 1.5, 2.1],\n",
        "}\n",
        "\n",
        "def input_fn(features, batch_size=256):\n",
        "    \"\"\"Функция ввода для прогноза.\"\"\"\n",
        "    # Преобразовываем входные данные в набор данных без меток.\n",
        "    return tf.data.Dataset.from_tensor_slices(dict(features)).batch(batch_size)\n",
        "\n",
        "predictions = classifier.predict(\n",
        "    input_fn=lambda: input_fn(predict_x))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "JsETKQo0rHvi"
      },
      "source": [
        "Метод `predict` возвращает итератор Python, который возвращает словарь результатов прогноза для каждого примера. Следующий код выводит несколько прогнозов и их вероятностей:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "Efm4mLzkrCxp"
      },
      "outputs": [],
      "source": [
        "for pred_dict, expec in zip(predictions, expected):\n",
        "    class_id = pred_dict['class_ids'][0]\n",
        "    probability = pred_dict['probabilities'][class_id]\n",
        "\n",
        "    print('Prediction is \"{}\" ({:.1f}%), expected \"{}\"'.format(\n",
        "        SPECIES[class_id], 100 * probability, expec))"
      ]
    }
  ],
  "metadata": {
    "colab": {
      "collapsed_sections": [],
      "name": "premade.ipynb",
      "toc_visible": true
    },
    "kernelspec": {
      "display_name": "Python 3",
      "name": "python3"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}
